///////////////////////////////////////////////////////////////
//  Copyright Christopher Kormanyos 2002 - 2011.
//  Copyright 2011 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
//
// This work is based on an earlier work:
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469

#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif

#include <boost/detail/lightweight_test.hpp>
#include <boost/array.hpp>
#include "test.hpp"

#if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128) && !defined(TEST_CPP_BIN_FLOAT)
#define TEST_MPF_50
#define TEST_MPFR_50
#define TEST_MPFI_50
#define TEST_BACKEND
#define TEST_CPP_DEC_FLOAT
#define TEST_FLOAT128
#define TEST_CPP_BIN_FLOAT

#ifdef _MSC_VER
#pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
#endif
#ifdef __GNUC__
#pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
#endif

#endif

#if defined(TEST_MPF_50)
#include <boost/multiprecision/gmp.hpp>
#endif
#if defined(TEST_MPFR_50)
#include <boost/multiprecision/mpfr.hpp>
#endif
#if defined(TEST_MPFI_50)
#include <boost/multiprecision/mpfi.hpp>
#endif
#ifdef TEST_BACKEND
#include <boost/multiprecision/concepts/mp_number_archetypes.hpp>
#endif
#ifdef TEST_CPP_DEC_FLOAT
#include <boost/multiprecision/cpp_dec_float.hpp>
#endif
#ifdef TEST_FLOAT128
#include <boost/multiprecision/float128.hpp>
#endif
#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
#endif

template <class T>
struct has_poor_large_value_support
{
   static const bool value = false;
};
#ifdef TEST_CPP_DEC_FLOAT
template <unsigned Digits10, class ExponentType, class Allocator, boost::multiprecision::expression_template_option ExpressionTemplates>
struct has_poor_large_value_support<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<Digits10, ExponentType, Allocator>, ExpressionTemplates> >
{
   static const bool value = true;
};
#endif
#ifdef TEST_CPP_BIN_FLOAT
template <unsigned Digits, boost::multiprecision::backends::digit_base_type DigitBase, class Allocator, class Exponent, Exponent MinE, Exponent MaxE, boost::multiprecision::expression_template_option ExpressionTemplates>
struct has_poor_large_value_support<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>, ExpressionTemplates> >
{
   static const bool value = true;
};
#endif

template <class T>
void test()
{
   std::cout << "Testing type: " << typeid(T).name() << std::endl;
   static const boost::array<const char*, 101u> data =
       {{
           "-9.71360659712083391437631022096936715962104815777147739346439739644168480837178969413799829610404829247283169084501281105e-1",
           "-5.95431113317256105006804890684659010940293672390817519158205264611725147142085353698349092164137652363446368483953564682e-1",
           "5.09924118934356013545988500545586843463766955556781588535384546070893806324487181574368899833574915659357543038822935347e-1",
           "9.90602974910637417521410554344955057938063175873799034495811832851567842600306335485818201417146475654562543760051881571e-1",
           "2.57755634110962773819397192502372718147953063328591480930319110437537556577887190430547163274290595074462686853519200826e-1",
           "-7.90852129665907861812449876176102241731921451584589870529143390612597378289323905030142878920134443274067663564142249906e-1",
           "-8.70636054394434218558219672958497111094237434037462776135170928197514857325641761722162169311905082223410873872693125021e-1",
           "1.16142192225871586802402588799179588339908282696987123538816621894316618250692422106879105583060486278819650782761165055e-1",
           "9.60641850565339311654365605083646127348817546384991780755200411966145627086231307074524787693440076802209868233548778731e-1",
           "6.28318825240308217440049590303028869715272770671179428040549526344092598897275498972932981684079339892035243316790587027e-1",
           "-4.73718579778960595001132927360485548840577209745936881040433718918629103032639945353908537818475936329314134212199346978e-1",
           "-9.95432766494621395340223548609251497842694553405493731879049259799325119533316838972006879914623359183523219011870805961e-1",
           "-2.97704078652633309130390182393607392013126109733352620573058826659738026681661456497779386104992235762190242017128767206e-1",
           "7.64723391125286889782047394187107836056829439952009227196240883193721606229047061163517791688110517783506991004016374431e-1",
           "8.90335717074674250432504838435892622513509178529392798127561987551398090841490265311069534613651712468228001675091153605e-1",
           "-7.47469618974513669394515485690188234127771130501791709462887130373371023385813212165673231177548426835629029005547008861e-2",
           "-9.48261778982069330544079494960981900232314056127899219497335245577354566418258722147558010380033694835705634428764954401e-1",
           "-6.60119969404606610211922488494059074732492583049845598285779387022002845776084527598443564095143849120847643366330179739e-1",
           "4.36693827009658961576344650626557410722590226545637608661764593658572210930294024902150766064738444736422263939746970132e-1",
           "9.98541130824430070642243744636010968399851408459030982248969144276197147611376115185206245742327729890090526273555800490e-1",
           "3.37137695943362070360548307779555944485385294617304662646987679063953108310365389494460188124285214040163147170304540339e-1",
           "-7.37272196933518190054375156317136276073182897209685319124536092629865074949247291797880288692223977281455156619510259042e-1",
           "-9.08495699506960201290293288218820500948312195353635174830883006841931398581001427066173033535720385301624330783999899511e-1",
           "3.32224697427099307204044509056982627738295866011152619834749776109067529453431741767996787924292629814505731320175556430e-2",
           "9.34241854135599266375493853147210486293657026766576383005045752264274587199837314096798394557243705656211732557069413970e-1",
           "6.90779551281016826784976005137338585011513089446563025258584317423906941741640583083551185645679047405447557105684226754e-1",
           "-3.98913888475082839741071010629509607776766095858433376450534753556286110518195743624946499527251336022805096741714382999e-1",
           "-9.99922692526403520897313527841668431397204867244750030781062964701898557028332255650446046614062333174844253917288331438e-1",
           "-3.75988292423704532504216998833472116186771022412627192871974303806891208635376610998425108046077306043945435504842144332e-1",
           "7.08546019140379445669962535829318394094758212505515423960726677977484727061149949358051741627739138448760095710063342839e-1",
           "9.25084597170819667485373176055260044057716794391569156042799693611964098948722923916237050181882167134906470192542857299e-1",
           "8.35947487571472125423673177137150279693224632368449469153892167972732129345714981936363891382927399742266512920038864004e-3",
           "-9.18606321039298722214219289469027246078943851192917449117591801249272620492502932760495762195965214412326830491755901723e-1",
           "-7.20244550473164405555518647469765134103488938825118543602681358279149452868549672550326500728323814331193184035259160414e-1",
           "3.60444097985855629825697367385029316833790934188475151408740160657889784929257301330229580694580194294034115152177674537e-1",
           "9.99575062430677992414643463029115424067356090568060307410717467085018957489304987413609313388961297483138454662118061646e-1",
           "4.14188682766963304833862149212585018360876819555612195218295874225032162838027842720351664698295767693697842043579048219e-1",
           "-6.78594534657286312316409269272929566493548786915986771929001823358451551885758307761400157853363173388867780400090112946e-1",
           "-9.40073722462713282312837596921874850901167502371739429501407718251639587081137893231736511487958940802467918593519005653e-1",
           "-4.99269632411748222821310824324558181913141458235676771744322439351386139493233963671531219603373207564905654915871172017e-2",
           "9.01382218619061521491363679812206948759377256420255657634443270431495336446996377562469573885297156497163691224107230524e-1",
           "7.48464012406957686684753003872919309910943477238245908909177973105841950470333390670719219379167068809799710776770734833e-1",
           "-3.21350982331168500558883709193541886146178412146971245706190880193067020283050714591560922441331235332970961845050217575e-1",
           "-9.97498841702838239659412520756556451623238132913559678626409839807628110807613195403956929948379909495726426243705794281e-1",
           "-4.51672806064485973599605876288778011355969815150135195358334589946828629430271875346142404286368814526016297993583170592e-1",
           "6.47469539349743367777844577149239337681085253251300560380374646379682072633705733561446355539618404778987844138766238618e-1",
           "9.53437154306238691456130012770111782377503876017231780889420296856266641153714110120975772709549811845909173386912105405e-1",
           "9.14081116365893107669584386407698218216480671014671832303147213716318806206478591012619084058741626713939006968851852873e-2",
           "-8.82599332954202005638662236444958997569939600897565089251125658458817750203393016337212996488633688567918453254294067039e-1",
           "-7.75389136447631492669594511701990356678047393586968390929688701894781023967621486245394406725747074772996680491766725244e-1",
           "0",
           "9.21877670451674413245307018032333288624288893879527153976730741889055419244554390143014969580425598422296522787223865492e-1",
           "7.14420247379307162288182477560228852605155250738051326022559557923361829606843109334201812861061126243914893718333771523e-1",
           "-3.68229061503980158220203193441625324286779814470455045264018328963975686564161509474566417124652588774892207244798533238e-1",
           "-9.99783810945210864429782835782052003838999970584938136857974918523615732378678641269300999292060748749245257644847852880e-1",
           "-4.06565491434208630299086167510578859920684132980243005899494321151205958987020300473732138517681916554185382528057861016e-1",
           "6.84710967469127345624707128760638003100107237269026812211460044517359789036617753689648451870956943571853410785082804567e-1",
           "9.37190534692875414284475879207349713030454322911019395907169592096165438597133651606167760904128838721803617281109050826e-1",
           "4.15761692057244148543310701200534576325308397337003695681679007540324069366547327722258885686349619359915993749152386902e-2",
           "-9.04970579658619470380865991258110513843850446973806499697900678159194774744593408797468966041695053471205276923200577190e-1",
           "-7.42894062146919717307486895770712177633720181625852464705801879158549930143011385755502810839808877188169347497140463278e-1",
           "3.29255843672460745277513964057060067396377984587222455665841087186879420769340447084849343957766905952270152874052907066e-1",
           "9.98054859318969984153930327705164465077718593220578997216979734167429154849012382322757855259404199572095265136279871773e-1",
           "4.44198837297768694342150710437773511448850303134514239359160353596186338967438818161771076138440975975069051604632938785e-1",
           "-6.53817599431343721060913145888825198919543068369083977787231740776950274433927919565042681494795499030972133972973154991e-1",
           "-9.50882691455803790808811011811129940528171185220498569922200361836899859377942311459807744784166538095896117442350480286e-1",
           "-8.30804396823694462619418608693397504202900045660409997788297791645107264729830105800672434941805906654953509298579082883e-2",
           "8.86498500176738212245618093138553877114943127333459437678466772704535139826656179981455385901664422134192971441152486596e-1",
           "7.70083171278361495868782270594413506070341191348346709317329019377797940394556787220273230008072684372906392335068211595e-1",
           "-2.89713235318575682157337623325710322388267200178020040738121279630672170355171163891332847251952971324782327373734923025e-1",
           "-9.94599945986602107902462030221489305674036413322184167100620086215068494963807086265519051279456167270901961176645890910e-1",
           "-4.81064018790479216363003919039401079745827607566793090566247167201506427394383426836725220489510187378030886775425254046e-1",
           "6.21793567954698234151923123976248746751871911018984490371928031737872104124834908200003970971778452547150523318639635937e-1",
           "9.62930462544790791995256817531759605974030310743258985429278608944994805716203043054967792555227147404499205611680348343e-1",
           "1.24441037037160425420824052419427892644210865386492893504553391973646623439822770473194845274620957661128504291608680469e-1",
           "-8.66493376243885476034533210550037276824055111358129259572484897399197578809821587005093985112028866251515011805996119334e-1",
           "-7.95940555954229526911811786010975888490876487056728372525209250018208474961217211282867562886053609351620626802054272020e-1",
           "2.49669618482792917975718339302754781070461300705127317300546100189317933291972223791458678771914034385073586648459580423e-1",
           "9.89425045617789945796335206411736550560149597573171983909624851636680028232543261568285131480585113303281176722731984359e-1",
           "5.17097284014384149171097163430722725596083616428334032893201431916692899725128152827282357887267679461332587145165393473e-1",
           "-5.88694253013035419947972745515246684318073372460957150709985237608958241550865774225576562359889367149484593966586261944e-1",
           "-9.73313013442224866478107643999632554759604190263325143130961313777287157745245701134838602677190253924612391775436901182e-1",
           "-1.65586435334914172055850479429458408174448669771862313204835451683387762284114799645762688524058144409210946183564694437e-1",
           "8.44989803230758608979729460217254170202748876564967551526138387646760352687916491884649142029664716335759879232648284164e-1",
           "8.20421500340164168068753907367027481963552257850283600606773656660614708517253273174848291641569969886126754639035754147e-1",
           "-2.09194241612317592929856274655591551278574667482924447651723415490434554354833563537792618079275726893013991849104465053e-1",
           "-9.82539107299636472172005507105476251789057582568202763534005396813858490465264145708502581273803767931004018272989858624e-1",
           "-5.52236319725534543207688775430217404447704139560595336544456138148662731976576062425879410116209671353021251780801885578e-1",
           "5.54576894095302137473562870411642498454159878739464625116831971740997730359915227524075717328436463081497500485416831879e-1",
           "9.82012389338213987427432686899213579991770436451929205950504261612336440523069987734051927060071228336651935114247230018e-1",
           "2.06445480789661722781085666935934466710665000093111315471318244086154187788240397407764949071589419997001126229699279918e-1",
           "-8.22024967814241172490083350373664443948382772873119098939533117836179462362265599942085298240078400862839510315401568501e-1",
           "-8.43483668915081157881609334416452212500481988371373212797897630926101856989377353686006695443683562952698091745372956064e-1",
           "1.68357099807987317797633647903674089665368628422558854222230995142941489911909308417314277825877040168111682241442337249e-1",
           "9.73954039060780508698548127540108987785881109985102169990241290387386676882934112332475075476604334818263785540220696343e-1",
           "5.86420359093869515237687266954561200160006212641211187483350874672859136679499954407470935299385535928011115437979374327e-1",
           "-5.19500491219840443397382144913775579016253538466887540765306393159738082663675375499840773403952929977354698339617261390e-1",
           "-9.89013546180296021750901758474634735102493497248279924875522015911873550276888689676425102442986261848126775556194306727e-1",
           "-2.46947514812703938169894550153319655995779907820829748198209521180129269232387596803077057086642606505827139155491603712e-1",
           "7.97638583669534812597149574893980942155226403291812660315816507318428697361476484505958849067790885048775312980075497096e-1",
           "8.65087179683067252708187359165577777305998628817518314353161876891989239932835217904989326717355654871984067712207255166e-1",
       }};

   boost::uintmax_t max_err = 0;
   for (unsigned k = 0; k < data.size(); k++)
   {
      static const T euler_gamma = static_cast<T>("5.77215664901532860606512090082402431042159335939923598805767234884867726777664670936947063291746749514631447249807082480960504014486542836224173997644923536253500333742937337737673942792595258247094916008735203948165670853233151776611528621199501507984793745085705740029921354786146694029604325421519e-1");
      T              val         = sin(euler_gamma * ((100 * k) - 5000));
      T              e           = relative_error(val, T(data[k]));
      unsigned       err         = e.template convert_to<unsigned>();
      if (err > max_err)
         max_err = err;
      val = sin(-euler_gamma * ((100 * k) - 5000));
      e   = relative_error(val, T(-T(data[k])));
      err = e.template convert_to<unsigned>();
      if (err > max_err)
         max_err = err;
   }
   std::cout << "Max error was: " << max_err << std::endl;
   BOOST_TEST(max_err < 5000000000uLL);

   static const boost::array<const char*, 51u> small_data =
       {{
           "0.010890646307437399028563191160252839599929232814970922208664909237494716181484215717644776933044418903207919912063594159099133490979634344811936925144447725948305353257042599564404885434349760121009797816724142318243738364307036155852011004353462651092012819894667485840322627440332163428546845499107471983896711023161969130462687924045508477090891879273259947713367290982391204265694893491531721581439",
           "0.029754394000520972141380267705677256353702996169858414168445272181777338962866552847084800544086743338130195210005002660881957584567978770485056322086472328896988088721899728258224129935989180857437073412730903070983582129359565450458299328041955729258476583848159389714290107649243089149974776893563078190705561325124542669960182002956940545214147678093802442811362846262655415145897575707676223535749",
           "0.04860754948595027759689273751438643634234576398271158524070718139962965653841137425728738193533514318422431877217110239554743968609870039776938201724688048349972662394084789924867267405853696017478160702683117974766657840965270625814482422398422216605490620054574252910928068433847115132429726072853170339113804838625536981361490008602432476302086066307320875870985443111858828925332085101376920451257",
           "0.067443401266329792365583268418977022587089806595860818790246293104463576184436096833111903064801552379988362224633198052490234517656318474005568709048710308123967082103235230201516378834855764348740505470176912466587139988300259624310153055247378188811239571439869254255368050758213303082097176168650573121101094016896349982672715603054645687782535250201448606757920212668324401846105554332382154705308",
           "0.086255244004175604199645786226683865650130764638142939010554245919172299560583634262067769465886944689883333394099120765964771092069938753689253686543017871063587988437235057514131760587649504670117933814486942187589706655157340717185354058186603027300571692666150552274324933749082047517987509942119060274537912867956274549119040817359639741746006374702951412541338483858389306953539029174581171144916",
           "0.10503638090893519164596691292161072193010174143933600597680115817738720676321226654184308409972393036413684625874294713490753271261380987552528236660688624108474124469034444076627315674234385578608111398112242272762722849083801773818689342174907858373883192220827687618321085007917387951532673599267211035785307947515638810735621964273183425401191468313574763898720597251843424536611952986478638938787",
           "0.12378012612096459891996422671239906394195356627713556749926735466337892925173796651675302282473738808218327028589606894825728784823540605065317506645900565980161901287116410208049542818796994171203890952761651470187834173644651508025088970034800067245131759655003164127161058084682831906406941473650395873577925901419536540828468001386512234321890242266327761400155849351025221609783793228816606096155",
           "0.14247980709161433833827358255114404185333478069639957369769805221957506649654851981837061160249376538785737485777248817812720592537597263252706422066438137522011148566625861552209380620325080441618503257506798981598559897331754555335688284111417797211888381141445522536739542765207936516297907076923899840216864191777039028622886076254231994264908278499537587536902686114072117102531777746791366147472",
           "0.16112876695857673825462942280040873226725445145336882995544646098546697397681955191516861690559627281570477802647683153249828731761062718487424104325152088763220776831248566486363299448443795266104568555186977695939803420793575204146124697832793773870449082377964029658283741910741804550762511379894890589132658450368609377005630322641674351408014813725947288936865021810537922503050280596331958949813",
           "0.17972036691564914131189073707203611766536704952071818203835281740755093560444625679032703078557333645546302532200674729781663838075105196332695024246509042831095553050804767663788014113177991938252225120228302734228632787082072480689719322299247090887229731260135165819595797392665106642595359433094386743214852929965104946276195924300495453775467378376551444126292108291215861133471208854009513721707",
           "0.19824798857606934571352609051549058593435535174283382080060738672122306773474119459815363636791069253463660528114022041674780565798655265640072669329819802234483545444085426470661233958030668844326674768815456315879868376252722369574694411591080512527683145774214215193268992508938562109669843137270238454905091555179756374512457742554641355319960601765568460966738628365652972463731882673979926092423",
           "0.2167050363285819704223187876642169717474346025766606244643176750460657731203611217470241676182041675112171974414875203007374497968642376196256262296063879827128970901451226217571636202438144440234868076467587220541438440149682254317134405302648426790500751310485432990930185087578150399032543990173811106465656404530116032387260432178319507278340110997943206401370789106214680733463126804159766688178",
           "0.23508493968539701289801441539326267060915175918342580386836036980227948313782327655061004506711767031388143537081826986030990557707922203603349984851809173788402101756510017046639631528282698404857654444279509591873678208318484036337040837844539190863615310872984455261973647897667843302241773795592355085118273592671348602240382153223466391512738221253451636183066773121830262978729780866153048605159",
           "0.2533811556212047542679161173582151227103672187769971543582388259784795155332622779547839459016647290250036005712168909799523370471647322112833886051217950625710683025675691585734514265087749450457714578451290681140064635291501640395753290532318406110106892218388811781561305402570000283806458134435822529043797962340420841850011846648265787470508569124672250211852546600514370101687713861131209463861",
           "0.27158717090241435065755609312085387589073221253701701142877476904254125053252466469600403650634482409879186635717002370089097070045821182432642232618427944489732133359996899812980722107011126957850576210476679069162561257167921627603536603943342268770727524690332400255408587654094512383349857596775777725888982277559281982571487656535560758087235441872907962373375423740325723506626374882319859924962",
           "0.28969650440578692965912855479777150523900698183973110358010443581781966348171378962307935462457921708108325003566673849851640304571019200113280406744551445148200341554501141174444530008329262826786160080931309057528673711507934822659456861163197618813727062179453555460400169858233923358238607875306523866767536243361049306545596678120228677505849040202788510059415993219975440657979707947898632705847",
           "0.30770270942563778634443222550824378057595253208974144909939396933701715445493088586920897452838893301853350676955400357197838773823140696209649573828382477454711986806154497998912926265388494228459988323524548750870702083339285969468391846533348589851520262990720843670148790211009236063622194282315540801467216625666505663699480592080398449845511909092071640909885054719301078547683325662349532658001",
           "0.32559937596878634249263192973385963275552570142977727375619908690982968889531407133936548327912894149757305868454394002531385820341045863161146695151908269553629121372700695833373968533510661265854738947940689721812230819575490874211279007289828369964583273676393398981064015459284982970048174649094549631109312941188691838118955683939990881732219088392629316401227525790752712758279892546851835776728",
           "0.34338013303643689435259984865624959352259286039436985939426483729323987764837568376066164703227630278807584950278626035763399164177429894322425866236150336898079573258157833074772287354310049676029566569737995054499018518699450946056626536479822852758163848528920078247789349605898976290484284018984355696648190967701849464571286257873661615051036433297599097073117151941857301740816310919312668936753",
           "0.36103865089217782674224266392907326208964452822379102503439414768728197653534265911503054023760783622236800804794470785631737993143180071550223728801984904852623160397230839644629077782630949486339104760008566935013234195735777070582106661423219379374522941522832331186147905332977726043795737008218909226025962294880541867964419424128310806148008435847967256901208159302482322730929744194185143496647",
           "0.37856864331529191294683302986737462527422720295203122486985051910813389831630458742420433021640718832999264813674938157273375290592788753133996741859965258034273428657399863159488519434113093863042179261649202584979828347495161391780592433454809420632605178105958049630938532568156789806946629309375790343585791884755866400295470651281289167454617624179556306285775538273640784278475358303871406797294",
           "0.3959638698385755489557710011250921602780605301308457595569865098132061251227321128681128349835212212508810246299921462519655630208347321575504292305860152320513799100372630595769065936291506594220617567642210250680560302662459931036815131767702563357378794733903424219866581554015722958062178902473414883933807190920961687912191470152974845756609418554739641361171541363409996648143043979357302190703",
           "0.41321813796987028521091431473013916161596830805293649687424341688961507413716621591649879163383882641673238540682782626959358955002216003316726344623613626809950993449214457071292961126188761860214007662067345193545393653191742497646193189677890657992964660139924463087072704096969748995358605459064076775540679952182100013584273877612509536257834358450242426357122974687246428904315337788603554112487",
           "0.43032530539651581726649227346608528709372859200683817125277384462849187532000288969537766724897319030479860713591459932866508254904869456423088312945970943686450425589907227275358186473310644458353392107693439475272544181726520566221333846008220008702070460626739342310039148106649726719665728169819714333172605016313499067227953767878741853545763313707499816244740855778447731454065384788859848319503",
           "0.44727928217193967651655712666040617006236300257644793444619887007723922383970962870988815495150987337761018019128790177957898245520422485269324604484642139354461290347689315448558082058132330317789105861674569680430563377440355102600184370927625450804550114009478901349833826102470780452480255838220723171955252412104006070322080932915859579006653276371401264439817338080069936810866666557553662506811",
           "0.46407403288360522126660904671571257203469668709200603873826642103612288853249598361813813213381052968904786566929537791978751985511297321991996818974870946807510786919602279514706154473236597480481149516597293844121405001964448599792635426082163120478756812832932606227610137817312140031064078333902425335570730565173883252754294319888872518149175050583958244086010074110878967984441526026195572046031",
           "0.48070357880154616464768530714893198018226307768872832018696934136162055774617690112915494983829868655926209174893609677823844628976682666861087174925649829592164380174433963170047900751735818142724368678683601091750819984658303806035572915499999180599872513173096429390456178642478189724903758698238722978406369084171804020040246631229610021517925007543961283845124822740019511921386188934760298241688",
           "0.49716200000672278683141570737786924159326600032981923078600441023882683095816876734389429898823686013764499093454507915253215528870989821318738227798745591597923864925733083640574132559603114206682739488541451077277291582357627881380008066440685837422009543184722898767087492264154499861112499590934108906196324393034778681622285346845867860458748417916763883649390228287689107774312170267691257606116",
           "0.51344343749844216224309565441486087365890516381683759696704839526386373494321578458551193514743669178342420835082611868891019193801223760604220552152028015878259509179672236586872004169442377393342941368136686044214656339879518691219516228434732537186028321245942076903928921929607502848888640267094590400556200402256089794954485061564115688273804254406706725374971267431122825004095102239220991848356",
           "0.52954209528009218542956877037980380998240467111773187487177084701668417706002935457309027480414979338624119758863233287969233845786459113619958146654397106933375312089626001011352424174223416515118670901639015699899005014886945323983797633471828049323917701068414699189471811508040323789047713536270617216249222074877291822920747392986535291960399633972613345908694327479738445245500914715996152461985",
           "0.54545224242244689926647810432697721723945987179773365856990386707254353534614807468692870318816991084937065603191754270239773531928848863926268254420020634174904439920465735399587679402503040251639815041072160696029528969373711375024524059535996077596844557011786411865071706766713049961515353664484996577751962474564968659755104983468313555304855249829815310291744255989014492588353749587481644931913",
           "0.56116821510380861353700162760755101727268623115746212675907859515911800480855365905235006799852352328451502804871577600277181740574994973635138803211912076695967558806493981733454148905054449991651227073996616835900542604367257843601995979944175684600136575098939764120745952964355353589317556067474680987527548079297833539998258342242865222215681747969549869015697939554127499557081626950060916329896",
           "0.57668441862626054773920164705882295031880435874490231795930393597704964539534854834250638055542815083463738683146430082379073149079998953871974990605030531115748567904948229002538680465351816034414085890696196467615521969543006224204433997063527288514443404935419253943724579872472854300703798475966107579038880496698051818375532546368197809806544115496171522444187250876233927302975709248591908972346",
           "0.59199532940731223634617420193837196766186356068263223313261061480558639436412180991021350240470913092271149633483820904350945127229180169976070379470147429711011056203078210298313829635000565303787641997857930629432231274870246836108452732993007541125359738273485061324228778750531830069944570036169084871305329515261365955383178502917713214334808810726412625844210978481512366368025275438632291862785",
           "0.60709549694622869462483067245797028399468956070763942538530335526853282815406226053099893555611232739741099281199863420254333016184720313024881100010161759837083928797224725640021095785125988238992410296927225409984765886863313873892022531648958451940083661715815760806237878803609330649695132473889046508160482887768573723088361332267243452286610176948724186843039692112797106039213976473403724518188",
           "0.62197954576434335539696684219824327976988998993669475584026026679831221725774460365328908947620452777457191790806959938899059379387140391128845696987642418506611453321626607869801717870254836897328796165084605948086983949944714226464644755644542238083403302661596239269476252222614109836597348873471190787660391585694078779921390758232910639208518119325492789999941075221166054973249356136808607130253",
           "0.6366421773186640485920116318191204083389644098160828009666722635549477083039305904975813615643101060893999315509501318081025137289051787335454356108133761354485193083183997634369795655283340428506642872565827559825155045924936470784378552800563136355526499002558162019410271880717338646318471375684163442601830537613691628498474632262547856029932241457937391840960919415488213025664314613747543749464",
           "0.65107817188809080279752785471799265973958362274943758073000075578938519480042543196041314945170036193559782763524413154927612489597355144799562963417455961310886431794132437757357185377007718709790504976900339191552944965308823754898079933186431693664015814010551367365293786806527034958873669211570906132849013497458819941168651227792824572805777219160376304646562062564773441718051418178414899683019",
           "0.6652823904315739978766556052897347198651017349760138699519597733553278561013395851136458951983261597283585391502588949649092379467069209284755289821255744166256794329589771465045421874634188329764638118238723545310838064785644468083837991172367935880462068347034222894524074808990476036821633127927532229213401486467496527893691588255513769781016943243185567913995336109327864083859254466073492381187",
           "0.67924977641755138662041086036801948989088186294785002709809874961811116536667286127777672928127306388394020078452402417993836722984523906631302047812425809759286220237826357465064765092612104224837992075711035615650942777454297235908308024053950635657488001916036801234116581671119069849133344664024677517075723660642709275823456343659009540444032487248071553674961012055521740306092600444870718199652",
           "0.69297535762401272778114932738244728669670875114228232862389083194872888693112134130021641463393969624412179768291914405554577080353247136859984307940401373940521815913274464950964347624918449081645304540343160683388727015489772202472645406318288749244334156857814927405528763108558137488794292057315715995191324964500528600378291562277858608403425720078390497455476055579003286296442406491998525563297",
           "0.70645424790855122905182233963742667718470686911515869065744744473731249895412640632516625097411541437953942564566468313798077366853928608154168668667806938130662439220702019172328936889436324187304262248463334787504456805683070026006307765178787997020889111556678907849442591478755800698808480163225125777511828352357189284217101098738405458071150544253514248561787426067001460586251699075230390564367",
           "0.71968164894777168289159927814596788937422432901416956306230349431557362414856173295064125294878325237342190029914430775648665560145040598898117000971783978541799092281781000633902779626437866517288284324732827083065703448279654800632624171861777710582293639879819116932680545313562525074940809403693475624332169458744562386580074420532959714281903926902622613852892104465683714186704831143197300465955",
           "0.73265285194543608674851404628602868786755398311878599262050209465658337331457767882450516660833910207846986678480603058221329185506983962144302950162737505562091432645466997334653618075359372680522922578429510783107155224742867979206003853893418268095936450823867623873015528453108944563276576646508412198497923383466470895808777876544429706485835161864475122029711660543090876323595451165397047981956",
           "0.74536323930873866831066285008063416514858255428941319323031554151661731879818806472410911187787504167842137286019020264008471692607030872105020489874402631524823767448432915438225335869622093354538021006314536198469136634364850042715775621307965524560308901397550829610851125072518884822515926626213581949190024268711827023522012804341871590177804438418738255381261594827085100659777173578154500251787",
           "0.75780828629211358196731753685850074775187628883294491833833279769413437275246840580617185041212744084038976069700142887035937511309419495512390089087847775651833369173386038513330257480188204696687136231267595399438343156895032682495327740328291738325217778497473260463740600852973600297913238958828132336080624048815574113414592522918778477418427876829087439774857073733879539765547872800792711360592",
           "0.76998356260799010064124325420889481428942836988785464918451704687709959533402569414853910266075223008145347866420469852220997470992987183595134711278161994827010482478666523199914707457365681979989417199177427808129308850228595726632468139527316915481709465938257650120793934685421343443942356060396291075752713480402305699120964704579260218579751719693291565685728074939857101460901984240449471777639",
           "0.78188473400392189344901888012886357289691591193533323711550248487573232160560048524966536928562079994581390209192526509899176077393862245482807165569409036943146775931090958041945317489351020506180957959482939768275851398130892970557450783138983566392455270904228057175489097967314871299150832712632639718878702471658606369540854496281803565819545728647765960328269135853132407415684491934581417388002",
           "0.79350756380552895006859336306152006552993066088382163294295016384877329185292344719536879395060919553184640006473875955257330264813115929942877156894433233876161573894628944452740080653935089289153173836334040374431360850336851424574668632837338016740333716530963434291489645017931035529052587483629111178971917421121398732580060101294617212337648611654041575132820234403350225337355214099696493406567",
           "0.80484791442470288298134387731514331459831415420391927496917008531718727007136925375073869996549995938671025493755987802316807560672754205522916341547950527416285009447065632296220924964603370109747266700136618832767813938243784759073035555035361911772169687111972294262096081393656654067512785827139608367560009298721819281091010743363153063005841441400130721362346287552727162527118465104052539630019",
           "0.81590174883253870457705586780548750833668862852238889952372206236774966573191832400412494946116015154305873210759963247859431688393192829248700535837612167242633896627292821666890819736549652534738107012873094812825219601489880060491958385552979476621004236099490018887651186347086675381603801017940808290855340870383683075409122477045713172106217670870448929077822708030574128623585863036730829850118",
       }};

   max_err = 0;
   for (unsigned k = 0; k < small_data.size(); k++)
   {
      static const T euler_gamma = static_cast<T>("5.77215664901532860606512090082402431042159335939923598805767234884867726777664670936947063291746749514631447249807082480960504014486542836224173997644923536253500333742937337737673942792595258247094916008735203948165670853233151776611528621199501507984793745085705740029921354786146694029604325421519e-1");
      T              val         = sin((euler_gamma + k) / 53);
      T              e           = relative_error(val, T(small_data[k]));
      unsigned       err         = e.template convert_to<unsigned>();
      if (err > max_err)
      {
         max_err = err;
      }
      val = sin(-(euler_gamma + k) / 53);
      e   = relative_error(val, T(-T(small_data[k])));
      err = e.template convert_to<unsigned>();
      if (err > max_err)
         max_err = err;
   }
   std::cout << "Max error was: " << max_err << std::endl;
   BOOST_TEST(max_err < 20);

   //
   // Test with some exact binary values as input - this tests our code
   // rather than the test data:
   //
   static const boost::array<boost::array<T, 2>, 9> exact_data =
       {{{{0.5, static_cast<T>("0.479425538604203000273287935215571388081803367940600675188616613125535000287814832209631274684348269086132091084505717418")}},
         {{0.25, static_cast<T>("0.247403959254522929596848704849389195893390980386965810676544830494398136043486821690984848527973792338327197752176516138")}},
         {{0.75, static_cast<T>("0.681638760023334166733241952779893935338382394659229909213625262151100388887003782753145274849781911981438190343146876189")}},
         {{std::ldexp(1.0, -20), static_cast<T>("9.53674316406105439710335272649306549801506698739838753888815787489707114648106832493113326022411646219016312547902694921e-7")}},
         {{2, static_cast<T>("0.909297426825681695396019865911744842702254971447890268378973011530967301540783544620126688924959380309967896742399486261")}},
         {{5, static_cast<T>("-0.958924274663138468893154406155993973352461543964601778131672454235102558086559603076995955429532866596530638461663378937")}},
         {{10, static_cast<T>("-0.544021110889369813404747661851377281683643012916223891574184012616757209640493425707075673894983216158293824238262832286")}},
         {{0, 0}},
         {{static_cast<T>("1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853399107404325664115332354692230477529111586267970406424055872514205135096926055277982231147447746519098221440548783296672306423782411689339158263560095457282428346173017430522716332410669680363012457064"), 1}}}};
   max_err = 0;
   for (unsigned k = 0; k < exact_data.size(); k++)
   {
      T        val = sin(exact_data[k][0]);
      T        e   = relative_error(val, exact_data[k][1]);
      unsigned err = e.template convert_to<unsigned>();
      if (err > max_err)
         max_err = err;
   }
   std::cout << "Max error was: " << max_err << std::endl;
   BOOST_TEST(max_err < 20);

#include "sincos.ipp"
   max_err = 0;
   for (unsigned k = 0; k < sincos.size(); k++)
   {
      T        val = sin(sincos[k][0]);
      T        e   = relative_error(val, sincos[k][1]);
      unsigned err = e.template convert_to<unsigned>();
      if (err > max_err)
         max_err = err;
   }
   std::cout << "Max error was: " << max_err << std::endl;
   BOOST_TEST(max_err < 20);

   if (has_poor_large_value_support<T>::value)
   {
      T bug_value = 12 / std::numeric_limits<T>::epsilon();
      for (unsigned i = 0; i < 20; ++i, bug_value *= 1.1)
      {
         BOOST_TEST(sin(bug_value) == 0);
      }
   }
}

int main()
{
#ifdef TEST_BACKEND
   test<boost::multiprecision::number<boost::multiprecision::concepts::number_backend_float_architype> >();
#endif
#ifdef TEST_MPF_50
   test<boost::multiprecision::mpf_float_50>();
   test<boost::multiprecision::mpf_float_100>();
#endif
#ifdef TEST_MPFR_50
   test<boost::multiprecision::mpfr_float_50>();
   test<boost::multiprecision::mpfr_float_100>();
#endif
#ifdef TEST_MPFI_50
   test<boost::multiprecision::mpfi_float_50>();
   test<boost::multiprecision::mpfi_float_100>();
#endif
#ifdef TEST_CPP_DEC_FLOAT
   test<boost::multiprecision::cpp_dec_float_50>();
   test<boost::multiprecision::cpp_dec_float_100>();
#ifndef SLOW_COMPLER
   // Some "peculiar" digit counts which stress our code:
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<65> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<64> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<63> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<62> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<61, long long> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<60, long long> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<59, long long, std::allocator<char> > > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<58, long long, std::allocator<char> > > >();
   // Check low multiprecision digit counts.
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<9> > >();
   test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<18> > >();
#endif
#endif
#ifdef TEST_FLOAT128
   test<boost::multiprecision::float128>();
#endif
#ifdef TEST_CPP_BIN_FLOAT
   test<boost::multiprecision::cpp_bin_float_50>();
   test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<35, boost::multiprecision::digit_base_10, std::allocator<char>, boost::long_long_type> > >();
#endif
   return boost::report_errors();
}
